﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using Microsoft.MediaCenter.Hosting;

namespace RMC
{
	internal class TcpInfoServer : IDisposable
	{
		private TcpListener tcpListener;
		private List<TcpClient> clients = new List<TcpClient>();
		private int port;
		private object threadLock = new object();
		private bool running;

		public TcpInfoServer(int port)
		{
			this.port = port;
		}

		public void Start()
		{
			running = true;
			isMute = AddInHost.Current.MediaCenterEnvironment.AudioMixer.Mute;
			volume = AddInHost.Current.MediaCenterEnvironment.AudioMixer.Volume;
			ThreadPool.QueueUserWorkItem(new WaitCallback(doProcess));

			// start server
			tcpListener = new TcpListener(IPAddress.Any, this.port);
			tcpListener.Start(2);

			tcpListener.BeginAcceptTcpClient(new AsyncCallback(tcpListener_AcceptTcpClient), null);
		}

		private void tcpListener_AcceptTcpClient(IAsyncResult asyn)
		{
			try
			{
				TcpClient tcpClient = tcpListener.EndAcceptTcpClient(asyn);

				lock (threadLock)
					clients.Add(tcpClient);

				SendMessage("204 Connected.\r\n", tcpClient);
				SendMessage("mute=" + isMute.ToString() + "\r\n");

				tcpListener.BeginAcceptTcpClient(new AsyncCallback(tcpListener_AcceptTcpClient), null);
			}
			catch (ObjectDisposedException)
			{
				System.Diagnostics.Debugger.Log(0, "RMC", "\n OnClientConnection: Socket has been closed\n");
			}
			catch (SocketException)
			{
				System.Diagnostics.Debugger.Log(0, "RMC", "\n OnClientConnection: Socket has been closed\n");
			}
		}

		public void SendMessage(string message)
		{
			foreach (TcpClient client in clients)
				SendMessage(message, client);
		}

		public void SendMessage(string message, TcpClient client)
		{
			if (client == null)
			{
				throw new ArgumentNullException("client");
			}

			byte[] buffer = System.Text.Encoding.UTF8.GetBytes(message);
			try
			{
				if (client.Client.Connected)
				{
					client.GetStream().Write(buffer, 0, buffer.Length);
				}
			}
			catch (IOException)
			{
				tcpListener_CloseTcpClient(client);
			}
		}

		private void tcpListener_CloseTcpClient(TcpClient client)
		{
			if (client != null)
			{
				lock (threadLock)
					clients.Remove(client);

				if (client.Connected)
					client.GetStream().Close();

				client.Close();
			}
		}

		public void Stop()
		{
			running = false;

			if (tcpListener != null)
				tcpListener.Stop();

			foreach (TcpClient client in clients)
			{
				if (client != null)
					tcpListener_CloseTcpClient(client);
			}
		}

		#region

		private bool isMute;
		private int volume;

		private void doProcess(object args)
		{
			while (running)
			{
				Thread.Sleep(500);

				if (isMute != AddInHost.Current.MediaCenterEnvironment.AudioMixer.Mute)
				{
					SendMessage("mute=" + AddInHost.Current.MediaCenterEnvironment.AudioMixer.Mute.ToString() + "\r\n");
					isMute = AddInHost.Current.MediaCenterEnvironment.AudioMixer.Mute;
				}
				if (volume != AddInHost.Current.MediaCenterEnvironment.AudioMixer.Volume)
				{
					SendMessage("volume=" + AddInHost.Current.MediaCenterEnvironment.AudioMixer.Volume.ToString() + "\r\n");
					volume = AddInHost.Current.MediaCenterEnvironment.AudioMixer.Volume;
				}
			}
		}

		#endregion


		#region IDisposable Members

		public void Dispose()
		{
			Stop();
		}

		#endregion
	}
}
